home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1995…tember: Reference Library / Dev.CD Sep 95 RL / Dev.CD Sep 95 RL.toast / mac / Technical Documentation / develop / develop Issue 22 code / Paper Juggling / Shell Files / ShellUtils.c < prev   
Encoding:
Text File  |  1995-04-18  |  33.6 KB  |  1,221 lines  |  [TEXT/MMCC]

  1. //---------------------------------------------------------------------
  2. //---------------------------------------------------------------------
  3. //
  4. //    Horrible Rickety Shell, by Dave Johnson
  5. //
  6. //    © Copyright 1985 - 1995 Anyone Who Wants It,
  7. //    All Rights Energetically Hurled as far away from me as possible.
  8. //    Use at your own (considerable) risk.
  9.  
  10.  
  11. #include    "PaperJuggling.h"
  12. #include     "DialogUtils.h"
  13. #include    <CodeFragments.h>
  14.  
  15. // Shell globals we need
  16. extern  Boolean        doneflag;
  17. extern MenuHandle    gShellMenuHandles[];
  18. extern short        gDocTitleHeight, gDocFrameWidth;     // Window Stats, for use in positioning
  19. extern GXPrintingEventUPP    gOurPrintingOverrideUPP;
  20.  
  21. // Dialog UPPs
  22. extern UserItemUPP        gBtnOutlineUPP;
  23. extern ModalFilterUPP    gStdKeyFilterUPP, gNumFilterUPP;
  24.  
  25. // temp prototype
  26. void CreateSampleImage(WindowPtr wind);
  27.  
  28. /* These are stolen from arith.c, so we don't have to include the ANSI library for
  29. 2 routines
  30. int
  31. abs(int i)
  32. {
  33.     if (i < 0)
  34.         return(-i);
  35.     return(i);
  36. }
  37.  
  38.  
  39. long
  40. labs(long i)
  41. {
  42.     if (i < 0)
  43.         return(-i);
  44.     return(i);
  45. }
  46.   */
  47.  
  48. /****************************************************
  49. Quickdraw Things...
  50. *****************************************************/
  51.  
  52. /*------------------------------------------------------------------------
  53. NewPixImage()            Creates pix image and inits the fields of the pixmap...
  54. ------------------------------------------------------------------------*/
  55.  
  56. Boolean NewPixImage(PixMapHandle ThePix, Rect *TheRect, short dpth)
  57. {
  58.     Ptr                    ThePtr;
  59.     long                Offrowbytes, ptrsize;
  60.     
  61.     Offrowbytes    =(((dpth * (TheRect->right - TheRect->left)) + 15) / 16) * 2;
  62.     ptrsize = (TheRect->bottom - TheRect->top) * Offrowbytes;
  63.     ThePtr = NewPtr(ptrsize);
  64.     if(MemError() != noErr)
  65.         return(false);
  66.     
  67.     (**ThePix).baseAddr = ThePtr;
  68.     (**ThePix).rowBytes = Offrowbytes + 0x8000;
  69.     (**ThePix).bounds = *TheRect;
  70.     (**ThePix).pixelSize = dpth;
  71.     (**ThePix).cmpCount = 1;
  72.     (**ThePix).cmpSize = dpth;
  73.     return(true);
  74. }
  75.     
  76.  
  77. /*------------------------------------------------------------------------
  78. NewBitMap()            Creates bit image and inits the fields of the bitmap...
  79. ------------------------------------------------------------------------*/
  80.  
  81. Boolean NewBitMap(BitMap *TheMap, Rect *TheRect)
  82. {
  83.     long    rb;
  84.     Ptr        ba;
  85.     
  86.     rb = ((TheRect->right - TheRect->left + 15) / 16) * 2;
  87.     ba = NewPtr(rb * (TheRect->bottom - TheRect->top));
  88.     if( MemError() == noErr)
  89.     {
  90.         TheMap->rowBytes = rb;
  91.         TheMap->baseAddr = ba;
  92.         TheMap->bounds = *TheRect;
  93.         return(true);
  94.     }
  95.     else
  96.         return(false);
  97. }
  98.  
  99. /*-------------------------------------------------------------------------
  100. CenterRect()             Centers theRect over thePt...
  101. --------------------------------------------------------------------------*/
  102. void CenterRect(Rect *theRect, Point *thePt)
  103. {
  104.     //  First home theRect... 
  105.     
  106.     OffsetRect(theRect, -theRect->left, -theRect->top);
  107.     
  108.     //  ...then center it over thePt 
  109.     
  110.      
  111.     thePt->h = thePt->h - (theRect->right / 2);
  112.     thePt->v = thePt->v - (theRect->bottom / 2);
  113.     OffsetRect(theRect, thePt->h, thePt->v);
  114. }
  115.  
  116. /*-------------------------------------------------------------------------
  117. Center()             Returns the center of the rect
  118. --------------------------------------------------------------------------*/
  119. Point Center(Rect *theRect)
  120. {
  121.     Point        pt;
  122.         
  123.     pt.h = theRect->left + ((theRect->right - theRect->left) / 2);
  124.     pt.v = theRect->top + ((theRect->bottom - theRect->top) / 2);
  125.     return(pt);
  126. }
  127.  
  128.  
  129. /*-------------------------------------------------------------------------
  130. These routines are from DTS Utilities
  131. --------------------------------------------------------------------------*/
  132. short    NumToolboxTraps(void)
  133. {
  134.     if (NGetTrapAddress(_InitGraf, ToolTrap) == NGetTrapAddress(0xAA6E, ToolTrap))
  135.         return (0x200);
  136.     else
  137.         return (0x400);
  138. }
  139.  
  140. TrapType    GetTrapType(short theTrap)
  141. {
  142.     //  OS traps start with A0, Tool with A8 or AA. 
  143.     if ((theTrap & 0x0800) == 0)                    //  per D.A. 
  144.         return (OSTrap);
  145.     else
  146.         return (ToolTrap);
  147. }
  148.  
  149. Boolean TrapAvailable(short theTrap)
  150. {
  151.     TrapType    theTrapType;
  152.  
  153.     theTrapType = GetTrapType(theTrap);
  154.     if ((theTrapType == ToolTrap) && ((theTrap &= 0x07FF) >= NumToolboxTraps()))
  155.         theTrap = _Unimplemented;
  156.  
  157.     return (NGetTrapAddress(_Unimplemented, ToolTrap) != NGetTrapAddress(theTrap,
  158.                   theTrapType));
  159. }
  160.  
  161. // Catenate 2 Str255s
  162. void    pcat255(StringPtr d, StringPtr s)
  163. {
  164.     short    i, j;
  165.  
  166.     if (((j = s[0]) + d[0]) > 255)
  167.         j = 255 - d[0];
  168.             //  Limit dest string to 255. 
  169.  
  170.     for (i = 0; i < j;) d[++d[0]] = s[++i];
  171. }
  172.  
  173. // Catenate 2 Str63s
  174. void    pcat63(StringPtr d, StringPtr s)
  175. {
  176.     short    i, j;
  177.  
  178.     if (((j = s[0]) + d[0]) > 63)
  179.         j = 63 - d[0];
  180.             //  Limit dest string to 63. 
  181.  
  182.     for (i = 0; i < j;) d[++d[0]] = s[++i];
  183. }
  184.  
  185. // Catenate 2 Strs, but make the result <= 31 characters, with s guaranteed to
  186. // be at the end
  187. void    AppendStr31(StringPtr d, StringPtr s)
  188. {
  189.     short    i, addLength = s[0], posIndex = d[0];
  190.     
  191.     // Keep suffix a reasonable length
  192.     if(addLength > 20)
  193.         addLength = 20;
  194.     
  195.     // Limit ending srting to 31
  196.     if ((posIndex + addLength) > 31)
  197.         posIndex = 31 - addLength;
  198.     
  199.     // Append
  200.     for (i = 0; i < addLength;) d[++posIndex] = s[++i];
  201.     d[0] = posIndex; // remember new length
  202. }
  203.  
  204. /* This routine concatenates 2 pascal strings, adding a space between if addSpace is true */ 
  205. char *PStrCat(Str255 str1, Str255 str2, Boolean addSpace)
  206. {
  207.     unsigned char    len1, len2, total;
  208.     
  209.     //  check lengths 
  210.     len1 = str1[0];
  211.     len2 = str2[0];
  212.     total = len1 + len2 + (addSpace ? 1 : 0);
  213.     if(total > 255)
  214.         return nil;
  215.     
  216.     if(addSpace)
  217.     {
  218.         str1[len1 + 1] = 0x20; //  Add the space 
  219.         len1 += 1;
  220.     }
  221.     BlockMove(&str2[1], &str1[len1 + 1], (long)len2);
  222.     str1[0] = total;
  223.     return (char *)str1;
  224. }
  225.  
  226. //  Just copies one string into another 
  227. void PStrCopy(Str255 src, Str255 dst)
  228. {
  229.     BlockMove(src, dst, (long)(src[0] + 1));
  230. }
  231.  
  232. /*---------------------------------------------------------------------------
  233.     Scroll Bar routines: Mostly stolen from TESample, but heavily modified, 
  234.     so even their mother wouldn't know 'em.
  235. ---------------------------------------------------------------------------*/
  236.  
  237. /* Here we resize the scrollbars (if needed) and adjust their values. It's a good 
  238. idea to hide the controls before calling this routine, otherwise
  239. it'll probably be pretty ugly for the user */
  240. void AdjustScrollbars(WindowPtr wind, Boolean needsResize)
  241. {
  242.     DocHandle        doc;
  243.     
  244.     doc = GetWindowDoc(wind);
  245.     if(doc == nil)
  246.         return;
  247.     
  248.     //  First move and resize the bars, if needed 
  249.     if ( needsResize )
  250.     {
  251.         /* First the horizontal one. Scroll bars actually hang over the edge of the 
  252.         window by one pixel, for some sick reason known only to the people who invented
  253.         it. */
  254.     
  255.         MoveControl((*doc)->hScroll, -1, wind->portRect.bottom - kScrollAdjust);
  256.         SizeControl((*doc)->hScroll, (wind->portRect.right - 
  257.                     wind->portRect.left) - (kScrollAdjust - kScrollTweak),
  258.                     kScrollWidth);
  259.         
  260.         //  Now the vertical one 
  261.         MoveControl((*doc)->vScroll, wind->portRect.right - kScrollAdjust, -1);
  262.         SizeControl((*doc)->vScroll, kScrollWidth, (wind->portRect.bottom - 
  263.                     wind->portRect.top) - (kScrollAdjust - kScrollTweak));
  264.     }
  265.     
  266.     //  Now adjust the values of the scrollbars 
  267.     AdjustScrollValues(wind);
  268. }
  269.  
  270. //  Adjusts the values of the scroll bars. 
  271. void AdjustScrollValues(WindowPtr wind)
  272. {
  273.     short            docSize, max;
  274.     short            oldValue, hScroll = 0, vScroll = 0;
  275.     Rect            viewRect;            
  276.     DocHandle        doc;
  277.     
  278.     doc = GetWindowDoc(wind);
  279.     if(doc == nil)
  280.         return;
  281.             
  282.     //  viewRect is the port of the window minus the scrollbars 
  283.     viewRect = wind->portRect;
  284.     viewRect.right -= kScrollAdjust;
  285.     viewRect.bottom -= kScrollAdjust;
  286.  
  287.     //  First Vertical 
  288.     oldValue = GetCtlValue((*doc)->vScroll);
  289.     docSize = (*doc)->contentSize.v;
  290.     
  291.     //  max is the amount of the picture that can't be seen 
  292.     max = docSize - viewRect.bottom;
  293.     if ( max < 0 ) max = 0;
  294.     SetCtlMax((*doc)->vScroll, max);
  295.     
  296.     /*     Adjust scroll value if necessary. It's necessary only if the current control 
  297.         value (which is also the number of lines scrolled off the top) is greater
  298.         than the control max. If so, then just set the control value to the max,
  299.         i.e. scrolled all the way down. */
  300.     if(oldValue > max)
  301.     {
  302.         SetCtlValue((*doc)->vScroll, max);
  303.         vScroll = oldValue - max;
  304.     }
  305.  
  306.     //  Now Horizontal 
  307.     oldValue = GetCtlValue((*doc)->hScroll);
  308.     //  lines is the number of horiz. pixels in the offscreen world 
  309.     docSize = (*doc)->contentSize.h;
  310.     //  max is the amount of the picture that can't be seen 
  311.     max = docSize - viewRect.right;
  312.     if ( max < 0 ) max = 0;
  313.     SetCtlMax((*doc)->hScroll, max);
  314.  
  315.     /*     Adjust scroll value if necessary. It's necessary only if the current control 
  316.         value (which is also the number of lines scrolled off the left) is greater
  317.         than the control max. If so, then just set the control value to the max,
  318.         i.e. scrolled all the way right. */
  319.     if(oldValue > max)
  320.     {
  321.         SetCtlValue((*doc)->hScroll, max);
  322.         hScroll = oldValue - max;
  323.     }
  324.     
  325.     if(hScroll != 0 || vScroll != 0)
  326.         DoScroll(wind, hScroll, vScroll, true);
  327. }
  328.  
  329.  
  330.  
  331. /* Determines how much to change the value of the scrollbar by and how
  332.     much to scroll the content, and then does both */
  333. pascal void ScrollActionProc(ControlHandle control, short part)
  334. {
  335.     short        amount, value, max;
  336.     WindowPtr    wind;
  337.     
  338.     if ( part != 0 ) {                //  if it was actually in the control 
  339.         wind = (*control)->contrlOwner;
  340.         switch ( part ) {
  341.             case inUpButton:
  342.             case inDownButton:        //  one line 
  343.                 amount = kLineScrollAmount;
  344.                 break;
  345.             case inPageUp:            //  one page 
  346.             case inPageDown:
  347.                 amount = kPageScrollAmount;
  348.                 break;
  349.         }
  350.         if ( (part == inDownButton) || (part == inPageDown) )
  351.             amount = -amount;        //  reverse direction for a downer 
  352.         
  353.         /* Pin the amount to the scroll bar range, set the value, and calculate the
  354.         change in value */
  355.         value = GetCtlValue(control);    //  get current value 
  356.         max = GetCtlMax(control);        //  and maximum value 
  357.         amount = value - amount;
  358.         if ( amount < 0 )
  359.             amount = 0;
  360.         else if ( amount > max )
  361.             amount = max;
  362.         SetCtlValue(control, amount);
  363.         amount = value - amount;        //  calculate the real change 
  364.         
  365.         //  Scroll the content the appropriate amount 
  366.         if ( amount != 0 )
  367.         {
  368.             DocHandle doc;
  369.             
  370.             doc = GetWindowDoc(wind);
  371.             
  372.             if(control == ((*doc)->hScroll))
  373.                 DoScroll(wind, amount, 0, true);
  374.             else
  375.                 DoScroll(wind, 0, amount, true);
  376.         }
  377.     }
  378. } //  ScrollActionProc 
  379.  
  380. //  Adds 2 scroll bars to the given window, adjusting them to fit 
  381. Boolean AddStdScrollBars(WindowPtr wind)
  382. {
  383.     ControlHandle    scrollHandle;
  384.     Rect            scrollRect;
  385.     short            min, max;
  386.     Boolean            rslt = false;
  387.     DocHandle        doc;
  388.     
  389.     doc = GetWindowDoc(wind);
  390.     if(doc == nil)
  391.         return false;
  392.         
  393.     /* These are just dummy values for the rect and the min and max. They will be 
  394.         adjusted in the AdjustScrollBars routine */
  395.     
  396.     //  First the horizontal one 
  397.     SetRect(&scrollRect, 0, 0, 10, 10);
  398.     min = 0;
  399.     max = 10;
  400.     scrollHandle = NewControl(wind, &scrollRect, "\p", false, 
  401.                 min, min, max, scrollBarProc, 0);
  402.                 
  403.     if(scrollHandle != nil)
  404.     {
  405.         //  Stash it in the document 
  406.         (*doc)->hScroll = scrollHandle;
  407.         
  408.         //  Now the vertical 
  409.         scrollHandle = NewControl(wind, &scrollRect, "\p", false, 
  410.                     min, min, max, scrollBarProc, 0);
  411.         if(scrollHandle != nil)
  412.         {
  413.             //  Stash it in the document 
  414.             (*doc)->vScroll = scrollHandle;
  415.             rslt = true;
  416.         }
  417.         else
  418.             DisposeControl((*doc)->hScroll);
  419.     }
  420.     if(rslt == true)
  421.     {
  422.         //  Set up the scroll bars for the current world 
  423.         AdjustScrollbars(wind, true);
  424.     }
  425.     return rslt;
  426. }
  427.  
  428. OSErr InitStdDoc(WindowPtr wind)
  429. {
  430.     DocHandle    doc;
  431.     OSErr         err = -1;
  432.     
  433.     doc = GetWindowDoc(wind);
  434.     if(doc == nil)
  435.         return -1;
  436.     
  437.     // Add scroll bars    
  438.     if(AddStdScrollBars(wind))
  439.     {
  440.         // Init the GX stuff
  441.         err = AddWindowGXStuff(wind);
  442.         if(err == noErr)
  443.         {
  444.             //  clear the dirty flag 
  445.             (*doc)->dirty = false;
  446.             
  447.             // These numbers are random: the app will put in real values
  448.             (*doc)->contentSize.h = 144;
  449.             (*doc)->contentSize.v = 144;
  450.         }
  451.     }
  452.     return err;
  453. }
  454.  
  455. Boolean CheckMachine(void)
  456. {
  457.     short        err, rslt = true;
  458.     long        gestResult;
  459.  
  460. //      Check the machine's capabilities to be sure we can run 
  461.     
  462.     //  Check for availability of Gestalt 
  463.     if(!TrapAvailable(_Gestalt))
  464.         return false;
  465.     
  466.     //  Check for availability of GWorlds 
  467.     err = Gestalt(gestaltQuickdrawVersion, &gestResult);
  468.     if(err != noErr)
  469.         return false;
  470.     if(gestResult < 0x0200) //  no 32-bit QD 
  471.         return false;
  472.     
  473.     //  Check for availability of FSSpec file routines 
  474.     err = Gestalt(gestaltFSAttr, &gestResult);
  475.     if(err != noErr)
  476.         return false;
  477.     if((gestResult & (1 << gestaltHasFSSpecCalls)) == 0)
  478.         return false;
  479.     
  480.     //  Check for availability of Standard Get/Put routines 
  481.     err = Gestalt(gestaltStandardFileAttr, &gestResult);
  482.     if(err != noErr)
  483.         return false;
  484.     if((gestResult & (1 << gestaltStandardFile58)) == 0)
  485.         return false;
  486.  
  487.     //  Check for availability of FindFolder routine 
  488.     err = Gestalt(gestaltFindFolderAttr, &gestResult);
  489.     if(err != noErr)
  490.         return false;
  491.     if((gestResult & (1 << gestaltFindFolderPresent)) == 0)
  492.         return false;
  493.  
  494.     //  Check for availability of TempMem routines 
  495.     err = Gestalt(gestaltOSAttr, &gestResult);
  496.     if(err != noErr)
  497.         return false;
  498.     if((gestResult & (1 << gestaltTempMemSupport)) == 0)
  499.         return false;
  500.  
  501.     // Check for Apple Event Manager
  502.     err = Gestalt(gestaltAppleEventsAttr, &gestResult);
  503.     if( err != noErr || !(gestResult & (1L >> gestaltAppleEventsPresent)) )
  504.         return false;
  505.     
  506.     return true;
  507. }
  508.  
  509. /* This routine calculates a document window's title bar height and frame width, for
  510. later use in positioning and growing windows. (Did you know that GrowWindow() takes
  511. as limits the size of the window's strucRgn, but returns the size of its portRect?) */
  512. void CalcWindowStats(void)
  513. {
  514.     WindowRecord    tempWind;
  515.     Rect            globalPortRect, strucRect, offScreenRect, deskRect;
  516.     
  517.     //  Make a small rectangle that is off the screen 
  518.     deskRect = (**GetGrayRgn()).rgnBBox;
  519.     SetRect(&offScreenRect, 0, 0, 32, 32);
  520.     OffsetRect(&offScreenRect, deskRect.left - 64, 0);
  521.     
  522.     /* Make a visible window that the user can't see. Only when a window is visible
  523.     can you find out its strucRgn dimensions */
  524.     NewWindow(&tempWind, &offScreenRect, "\p", true, documentProc, (WindowPtr)-1, false, 0);
  525.     
  526.     /* OK, we have a window. Now calculate the info we need. First we need
  527.     to globalize the portRect and get the strucRect of the window */
  528.     globalPortRect = ((GrafPtr)(&tempWind))->portRect;
  529.     SetPort((GrafPtr)&tempWind);
  530.     LocalToGlobal(&topLeft(globalPortRect));
  531.     LocalToGlobal(&botRight(globalPortRect));
  532.     strucRect = (*(((WindowPeek)(&tempWind))->strucRgn))->rgnBBox;
  533.     
  534.     /* Calculate the window's title bar height. I'm not entirely sure why you need to
  535.     subtract 1 here, but Craig Prouse did it in his Window Zoom routine, and I'm sure
  536.     he had a good reason for it, so I'll do it too. */
  537.     gDocTitleHeight = globalPortRect.top - 1 - strucRect.top;
  538.     
  539.     //  Calculate the width of the window's right side frame 
  540.     gDocFrameWidth = strucRect.right - 1 - globalPortRect.right;
  541.     
  542.     //  All Done, kill the window 
  543.     CloseWindow((WindowPtr)&tempWind);
  544. }
  545.  
  546. // Get the document out of the window
  547. DocHandle    GetWindowDoc(WindowPtr wind)
  548. {
  549.     DocHandle    doc = nil;
  550.  
  551.     if ( wind != nil && IsAppWindow(wind) )
  552.         doc = (DocHandle) GetWRefCon(wind);
  553.     
  554.     return doc;
  555. }
  556.  
  557. //  Returns true if the given window is user kind and not nil 
  558. Boolean IsAppWindow (WindowPtr wind)
  559. {
  560.     return    ((((WindowPeek) wind)->windowKind == userKind) && (wind != nil));
  561. }
  562.  
  563. /* This routine gets any pending activate and update events from the queue and processes
  564. them. Used when saving changes, when a window is brought to the front behind a dialog */
  565. void DoActivateUpdate(void)
  566. {
  567.     EventRecord        event;
  568.     GrafPtr            oldport;
  569.     
  570.     //  First do activates 
  571.     while(GetNextEvent(activMask, &event) == true)
  572.     {
  573.         AppActivate((WindowPtr)event.message, event.modifiers & activeFlag);
  574.     }
  575.     
  576.     //  Then updates 
  577.     while(GetNextEvent(updateMask, &event) == true)
  578.     {
  579.         GetPort(&oldport);
  580.         SetPort((WindowPtr)event.message);
  581.         BeginUpdate((WindowPtr)event.message);
  582.         
  583.         AppUpdate((WindowPtr)event.message);
  584.         
  585.         EndUpdate((WindowPtr)event.message);
  586.         SetPort(oldport);
  587.     }
  588. }
  589.     
  590.  
  591. /* Stolen from Craig Prouse's famous DoWZoom routine, and modified for my own devious 
  592.     purposes. I tried to copy the Finder's behavior: If I can just size the window bigger 
  593.     and the result will stay completely on the same device the window is already on, I do 
  594.     that. Otherwise the window is zoomed to the top left of the appropriate device. This 
  595.     routine assumes up front that we are running in a Color Quickdraw environment, i.e
  596.     there is the possibility of multiple devices. It does NOT zoom the window, it just
  597.     calculates the appropriate rect and installs it in the window's stdState field */
  598. void ReadyWZoom(WindowPtr wind, short zoomDir, short maxH, short maxV)
  599. {
  600.     //  Only if we are zooming out do we need to go through all these gyrations 
  601.     if(zoomDir == inZoomOut)
  602.     {
  603.         Rect        globalPortRect, theSect, zoomRect, deviceRect;
  604.         GDHandle    nthDevice, dominantGDevice;
  605.         long        sectArea, greatestArea;
  606.         
  607.         globalPortRect = wind->portRect;
  608.         LocalToGlobal(&topLeft(globalPortRect));
  609.         LocalToGlobal(&botRight(globalPortRect));
  610.         
  611.         /* Walk the device list looking for the device that contains most of the 
  612.             window, or all of the window */
  613.         nthDevice = GetDeviceList();
  614.         greatestArea = 0;
  615.         while(nthDevice != nil)
  616.         {
  617.             SectRect(&globalPortRect, &(*nthDevice)->gdRect, &theSect);
  618.             
  619.             /* if the intersection is equal to the portRect, then the window is fully
  620.                 contained on this device: we can stop looking */
  621.             if(EqualRect(&globalPortRect, &theSect))
  622.             {
  623.                 dominantGDevice = nthDevice;
  624.                 break;
  625.             }
  626.             sectArea = (long)(theSect.right - theSect.left) * (theSect.bottom - theSect.top);
  627.             if(sectArea > greatestArea)
  628.             {
  629.                 greatestArea = sectArea;
  630.                 dominantGDevice = nthDevice;
  631.             }
  632.             nthDevice = GetNextDevice(nthDevice);
  633.         }
  634.         
  635.         /* Now let's see if we can just increase the window's size to the max and stay
  636.             completely on the dominantGDevice */
  637.         SetRect(&zoomRect, globalPortRect.left, globalPortRect.top,
  638.                     globalPortRect.left + maxH, globalPortRect.top + maxV);
  639.         deviceRect = (*dominantGDevice)->gdRect;
  640.         InsetRect(&deviceRect, 4, 4); //  Keep window 4 pixels away from edges 
  641.         SectRect(&zoomRect, &deviceRect, &theSect);
  642.  
  643.         /* if the intersection is equal to the zoomRect, then the zoomRect is fully
  644.             contained on this device: we have our new zoomRect. Otherwise we need to
  645.             do a little more work. */
  646.         if(!EqualRect(&zoomRect, &theSect))
  647.         {
  648.             short    bias;
  649.             
  650.             /* Calculate the height of the window's title bar. Actually, in this app
  651.                 I already have, but in the interests of easy cut and paste I'll do 
  652.                 it again */
  653.             bias = globalPortRect.top - 1 - (*(((WindowPeek)wind)->strucRgn))->rgnBBox.top;
  654.             
  655.             /* Now we can create our zoom rectangle. Account for MBarHeight if on the
  656.                 main device */
  657.             if(dominantGDevice == GetMainDevice())
  658.                 bias += GetMBarHeight();
  659.             zoomRect.left = deviceRect.left;
  660.             zoomRect.top = deviceRect.top + bias;
  661.             
  662.             /* Set right and bottom to either the max size or the deviceRect,
  663.                 whichever is less */
  664.             if(zoomRect.left + maxH > deviceRect.right)
  665.                 zoomRect.right = deviceRect.right;
  666.             else
  667.                 zoomRect.right = zoomRect.left + maxH;
  668.             
  669.             if(zoomRect.top + maxV > deviceRect.bottom)
  670.                 zoomRect.bottom = deviceRect.bottom;
  671.             else
  672.                 zoomRect.bottom = zoomRect.top + maxV;
  673.         }
  674.         
  675.         //  Load the rect into the stdState of the window 
  676.         (*(WStateDataHandle)(((WindowPeek)wind)->dataHandle))->stdState = zoomRect;
  677.       }
  678. }
  679.  
  680.  
  681. /* Sets the clip of the window to exclude the scroll bars. Assumes the port is set 
  682. already */
  683. void CloseClip(WindowPtr wind)
  684. {
  685.     Rect    clip;
  686.     
  687.     clip = wind->portRect;
  688.     clip.right -= kScrollAdjust;
  689.     clip.bottom -= kScrollAdjust;
  690.     ClipRect(&clip);
  691. }
  692.  
  693. void DoErrorAlert(short stringID1, short error)
  694. {
  695.     Str255    string1, string2;
  696.     
  697.     GetIndString(string1, kErrorStringsID, stringID1);
  698.     if(error != 0)
  699.         NumToString((long)error, string2);
  700.     else
  701.         *string2 = 0;
  702.  
  703.     ParamText(string1, string2, "\p", "\p");
  704.     StopAlert(kErrorAlertID, nil);
  705. }
  706.  
  707. //  Puts up the "Save Changes?" dialog, and returns the number of the button hit 
  708. short SaveChangesDlog(void)
  709. {
  710.     Str255        fileName;
  711.     DialogPtr    dptr;
  712.     short        hit, kind;
  713.     Handle        itmhndl;
  714.     Rect        rect;
  715.     Boolean        rslt = false;
  716.  
  717.     #define NOSAVEBUTTON     4
  718.     
  719.     /* Get the title of the front window, and use ParamText to set it in
  720.         the dialog */
  721.     GetWTitle(FrontWindow(), fileName);
  722.     ParamText(fileName, "\p", "\p", "\p");
  723.     
  724.     dptr = GetNewDialog(kSaveChangesDlogID, nil, (WindowPtr)(-1));
  725.     if(dptr == nil)
  726.     {
  727.         DoErrorAlert(kNoResStr, 0);
  728.         return iCancelButton;
  729.     }
  730.     
  731.     //  OK button Outline 
  732.     GetDItem(dptr, iOKOutline, &kind, &itmhndl, &rect);
  733.     SetDItem(dptr, iOKOutline, userItem, (Handle)gBtnOutlineUPP, &rect);
  734.     
  735.     //  Do it... 
  736.     ShowWindow(dptr);
  737.     while(true)                                    //  Loop until break...
  738.     {
  739.         Boolean     out = false;
  740.         
  741.         ModalDialog(gStdKeyFilterUPP, &hit);
  742.         switch(hit)
  743.         {
  744.             case iOKButton:
  745.             case iCancelButton:
  746.             case NOSAVEBUTTON:
  747.                 rslt = hit;
  748.                 out = true;
  749.                 break;
  750.     
  751.             default:                    //  Anything else hit... 
  752.                 continue;
  753.         }
  754.         if(out)
  755.             break;
  756.     }
  757.     DisposDialog(dptr);
  758.     return rslt;
  759. }
  760.  
  761. /*     This routine closes all the windows
  762.     It returns true if the caller should proceed, or false if the user canceled along the way. */
  763. Boolean CloseAllDocs(void)
  764. {
  765.     Boolean        quitting;
  766.     WindowPtr    wind;
  767.     
  768.     wind = FrontWindow();
  769.     if(wind == nil)
  770.         return true; // Done
  771.         
  772.     //  Loop through all windows
  773.     quitting = true;
  774.     while(quitting == true && wind != nil)
  775.     {
  776.         quitting = DoClose(wind);
  777.         wind = (WindowPtr)((WindowPeek)wind)->nextWindow;
  778.         if(quitting)
  779.             DoActivateUpdate(); // allow windows behind to activate and draw
  780.     }
  781.     return quitting;    
  782. }
  783.  
  784. /* This routine positions and sizes the window (assumed hidden) appropriately 
  785. for a "new" document and then shows it. The size is assumed to be already
  786. set up. */
  787. void SetUpAndShowWindow(WindowPtr wind)
  788. {
  789.     Rect        deviceRect, docRect;
  790.     GDHandle    theDevice;
  791.     short         horSize, verSize, wTop, wLeft;
  792.     DocHandle    doc;
  793.     
  794.     doc = GetWindowDoc(wind);
  795.     if(doc == nil)
  796.         return;
  797.         
  798.     /* Set up a rect on the deepest device that is inset 4 pixels from the edges.
  799.         Note that if it is the Main device we have to take into account the menu bar. */
  800.     deviceRect = (**GetGrayRgn()).rgnBBox;     //  Get rect of entire desktop 
  801.     theDevice = GetMaxDevice(&deviceRect);    //  Get the deepest device 
  802.     deviceRect = (*theDevice)->gdRect;        //  Get its rect 
  803.     InsetRect(&deviceRect, 4, 4);            //  Leave a 4 pixel border on the edges 
  804.     if(theDevice == GetMainDevice())        //  Add the menu bar height if the main device 
  805.         deviceRect.top += GetMBarHeight();
  806.     
  807.     // Now set up doc rect
  808.     docRect.top = docRect.left = 0;
  809.     docRect.right = (*doc)->contentSize.h;
  810.     docRect.bottom = (*doc)->contentSize.v;
  811.     
  812.     /* OK, Need to add the height of the title bar 
  813.         to the vertical coordinate */
  814.     wLeft = deviceRect.left;
  815.     wTop = deviceRect.top + gDocTitleHeight;
  816.     MoveWindow(wind, wLeft, wTop, false);
  817.     
  818.     /* Now calculate a good size for the window. We'd like to make it the full size
  819.     (plus scroll bars), but if it would then hang over the edges of the screen,
  820.     we make it smaller. */
  821.     horSize = docRect.right + kScrollAdjust;
  822.     if(wLeft + horSize > deviceRect.right) //  hangs off the right 
  823.         horSize = deviceRect.right - wLeft;
  824.     verSize = docRect.bottom + kScrollAdjust;
  825.     if(wTop + verSize > deviceRect.bottom) //  hangs off the bottom 
  826.         verSize = deviceRect.bottom - wTop;
  827.     
  828.     //  Size it, and reset the clip 
  829.     SizeWindow(wind, horSize, verSize, false);
  830.     SetPort(wind);
  831.     ClipRect(&wind->portRect);
  832.     ResetGXClip(wind);
  833.     
  834.     //  Make sure the scrollbars are presentable 
  835.     AdjustScrollbars(wind, true);
  836.     
  837.     //  OK, we're ready. Show the window 
  838.     ShowWindow(wind);
  839. }
  840.  
  841.  
  842. // =====================================================================
  843. // GX-specific routines
  844.  
  845. // See if QuickDraw GX is available.If not, return false
  846. Boolean CheckQuickDrawGX (void)
  847. {
  848.     long                theFeature;
  849.  
  850.     if ( (Gestalt(gestaltGraphicsVersion, &theFeature) != noErr) ||
  851.           (Gestalt(gestaltGXPrintingMgrVersion, &theFeature) != noErr))
  852.         return false;   // QuickDraw GX is not available
  853.     
  854. #ifdef powerc
  855.     // This is a sanity check to see if the PowerPC QuickDrawGXLib is installed.
  856.     // Since we are "weak" linked to QuickDrawGXLib, the Process Manager will
  857.     // launch us even if QuickDrawGXLib is missing.  If it's missing, the
  858.     // Code Fragment Manager will leave the address of the functions we call
  859.     // unresolved, and we would crash if we tried to call that function.  So,
  860.     // we do a check here and should be prepared to exit gracefully if the 
  861.     // library is missing.  This could happen if the user has installed a
  862.     // 68K only version of QuickDraw GX.  It could also happen if the user has
  863.     // taken the QuickDraw GX extension out of the Extensions Folder.  
  864.     //
  865.     // Note - We could check this against any function we call in the library.
  866.     // GXNewGraphicsClient is the first function we call, so it's convenient.
  867.     
  868.     if ( (int)GXNewGraphicsClient == kUnresolvedSymbolAddress ) 
  869.         return false;   // QuickDraw GX is not available in Power Mac
  870. #endif
  871.     
  872.     return true;
  873. }
  874.  
  875. // Get the gxJob out of the window
  876. gxJob GetWindowGXJob(WindowPtr wind)
  877. {
  878.     gxJob        docJob = nil;
  879.     DocHandle    doc = nil;
  880.  
  881.     if ( wind != nil )
  882.     {
  883.         doc = GetWindowDoc(wind);
  884.         if ( doc != nil )
  885.             docJob = (*doc)->docJob;
  886.     }
  887.     return docJob;
  888. }
  889.  
  890. // Get the page shape out of the window
  891. gxShape GetWindowGXShape (WindowPtr wind)
  892. {
  893.     gxShape    docPage = nil;
  894.     DocHandle    doc = nil;
  895.  
  896.     if ( wind != nil )
  897.     {
  898.         doc = GetWindowDoc(wind);
  899.         if ( doc != nil )
  900.             docPage = (*doc)->docPage;
  901.     }
  902.     return docPage;
  903. }
  904.  
  905. // Get the content port out of the window
  906. gxViewPort GetWindowGXPort(WindowPtr wind)
  907. {
  908.     gxViewPort    docPort = nil;
  909.     DocHandle    doc = nil;
  910.  
  911.     if ( wind != nil )
  912.     {
  913.         doc = GetWindowDoc(wind);
  914.         if ( doc != nil )
  915.             docPort = (*doc)->docPort;
  916.     }
  917.     return docPort;
  918. }
  919.  
  920. OSErr AddWindowGXStuff(WindowPtr wind)
  921. {
  922.     OSErr        err;
  923.     DocHandle    doc;
  924.     gxJob        docJob;
  925.     gxShape        docPage;
  926.     gxViewPort    docPort, windowPort;
  927.     
  928.     // Attach a default gxViewPort to it
  929.     windowPort = GXNewWindowViewPort(wind);
  930.     
  931.     // Create a print job for this document and save it.  This will be the same as the system default until
  932.     // the user goes through the dialogs for Page Setup or Print…
  933.     err = GXNewJob(&docJob);
  934.     if(err == noErr)
  935.     {
  936.         // Now install our application override for PrintingEvent so that we can
  937.         // support the new movable-modal printing dialog boxes.
  938.         GXInstallApplicationOverride(docJob, gxPrintingEvent, gOurPrintingOverrideUPP);
  939.         
  940.         // Create the child view port for scrolling and attach to parent,
  941.         docPort = GXNewViewPort(GXGetViewPortViewGroup(windowPort));
  942.         GXSetViewPortParent(docPort, windowPort);
  943.  
  944.         // Create the page shape. We set the unique items attribute to make sure that each item
  945.         // added to the picture has a unique reference. If this attribute was not set, we would
  946.         // not see all copies of anything we add to the shape multiple times -- we'd just see
  947.         // the last version added.        
  948.         docPage = GXNewShape(gxPictureType);
  949.         SetDeepShapeViewPort(docPage, docPort);
  950.         if(docPage != nil)
  951.         {
  952.             doc = GetWindowDoc(wind);
  953.             if(doc != nil)
  954.             {
  955.                 (*doc)->docJob = docJob;
  956.                 (*doc)->docPage = docPage;
  957.                 (*doc)->docPort = docPort;
  958.             }
  959.         }
  960.         else
  961.             err = -108;
  962.     }
  963.     return err;
  964. }
  965.  
  966. // This function returns a fixed point rectangle which represents the portRect of the
  967. // window. The rectangle returned is used as the new clip shape for the content ViewPort.
  968. void GetGXWindowBounds(WindowPtr wind, gxRectangle *gxRectPtr)
  969. {
  970.     //    Convert the QuickDraw rectangle into a QuickDraw GX fixed point rectangle.
  971.     ShortRectToFixed(&wind->portRect, gxRectPtr);
  972. }
  973.  
  974. // resets the clip shape of the content ViewPort after the user has resized the window.           
  975. void ResetGXClip(WindowPtr wind)
  976. {
  977.     gxRectangle    viewRect;
  978.     gxShape        clipShape;
  979.     gxViewPort    docPort;
  980.  
  981.     //    Return a fixed point rectangle in "viewRect" which represents the portRect of the
  982.      //    window. This shape will be used as the new clip shape for "gcontentViewPort".
  983.     GetGXWindowBounds(wind, &viewRect);
  984.  
  985.     // Adjust our viewRect to accommodate the scroll bars
  986.     viewRect.right -= ff(kScrollAdjust);    
  987.     viewRect.bottom -= ff(kScrollAdjust);
  988.  
  989.     //    get the content port
  990.     docPort = GetWindowGXPort(wind);
  991.     if(docPort != nil)
  992.     {
  993.         // Create clip shape, set clip of port, and dispose shape
  994.         clipShape = GXNewRectangle(&viewRect);
  995.         GXSetViewPortClip(docPort, clipShape);
  996.         GXDisposeShape(clipShape);
  997.     }
  998. }
  999.  
  1000. // This procedure adjusts the mapping of our content viewPort and optionally 
  1001. // scrolls the contents of the window
  1002. void DoScroll(WindowPtr wind, short hScroll, short vScroll, Boolean draw)
  1003. {
  1004.     Rect            scrollRect;
  1005.     RgnHandle        myRgn;
  1006.     gxMapping        viewPortMapping;
  1007.     gxViewPort        docPort;
  1008.     
  1009.     docPort = GetWindowGXPort(wind);
  1010.     if(docPort == nil)
  1011.         return;
  1012.     
  1013.     //    The user has scrolled the contents of the window, therefore we need
  1014.     //    to update the mapping of the content ViewPort to reflect this change.
  1015.     GXGetViewPortMapping(docPort, &viewPortMapping);
  1016.     MoveMapping(&viewPortMapping, ff(hScroll), ff(vScroll));
  1017.     GXSetViewPortMapping(docPort, &viewPortMapping);
  1018.  
  1019.     if(draw)
  1020.     {
  1021.         /* Scroll contents of window except for scroll bars */
  1022.         scrollRect = wind->portRect;
  1023.         scrollRect.right -= kScrollAdjust;
  1024.         scrollRect.bottom -= kScrollAdjust;
  1025.     
  1026.         SetPort(wind);
  1027.         myRgn = NewRgn();
  1028.         ScrollRect(&scrollRect, hScroll, vScroll, myRgn);
  1029.  
  1030.         // Add myRgn to the update region and draw
  1031.         InvalRgn(myRgn);
  1032.         BeginUpdate(wind);
  1033.         AppDrawContent(wind);
  1034.         EndUpdate(wind);
  1035.         DisposeRgn(myRgn);
  1036.     }
  1037. }
  1038.  
  1039. //--------------------------
  1040. //    What follows are all the printing routines from QDGX shell printing.c, renamed
  1041. //------------------------
  1042.  
  1043. /**\
  1044. |**| ---------------------------------------------------------------------
  1045. |**| MyPrintingEventOverride()
  1046. |**| Override for GXPrintingEvent.  It allows us to update our windows
  1047. |**| when the moveable modal printing dialogs are moved.  Keep this in your
  1048. |**| main segment, which will always be loaded when GX tries to call the routine.
  1049. |**| ---------------------------------------------------------------------
  1050. \**/
  1051. OSErr MyGXPrintingEventOverride (EventRecord *event, Boolean filterEvent)
  1052. {
  1053.     // Handle events in whatever way is appropriate.
  1054.     // MyDoEvent is our generic event handler.
  1055.  
  1056.     if ( !filterEvent )
  1057.         switch(event->what)
  1058.         {
  1059.             case mouseDown:
  1060.             case keyDown:
  1061.             case autoKey:
  1062.                 break;
  1063.             
  1064.             default:
  1065.                 DoEvent(event);
  1066.                 break;
  1067.         }
  1068.     return noErr;
  1069. }
  1070.  
  1071.  
  1072. /**\
  1073. |**| ---------------------------------------------------------------------
  1074. |**| SetUpEditMenuRec()
  1075. |**| This routine sets up an gxEditMenuRecord which references our edit
  1076. |**| menu.  This structure is used by the GXJobDefaultFormatDialog and 
  1077. |**| GXJobPrintDialog calls to allow cut, copy, & paste operations from
  1078. |**| the dialogs.
  1079. |**| ---------------------------------------------------------------------
  1080. \**/
  1081. void SetUpGXEditMenuRec (gxEditMenuRecord *edMenuRec)
  1082. {
  1083.  
  1084.     edMenuRec->editMenuID = kEditMenuID;
  1085.     edMenuRec->cutItem = iCut;
  1086.     edMenuRec->copyItem = iCopy;
  1087.     edMenuRec->pasteItem = iPaste;
  1088.     edMenuRec->clearItem = iClear;
  1089.     edMenuRec->undoItem = iUndo;
  1090. }
  1091.  
  1092.  
  1093. /**\
  1094. |**| ---------------------------------------------------------------------
  1095. |**| DoFormat()
  1096. |**| This routine performs GX's equivalent of the Page Setup (PrStlDialog) 
  1097. |**| call of the old printing architecture.
  1098. |**| ---------------------------------------------------------------------
  1099. \**/
  1100. OSErr DoGXFormatDialog (WindowPtr wind, gxDialogResult    *result)
  1101. {
  1102.     OSErr                err = noErr;        
  1103.     gxEditMenuRecord    edMenuRec;
  1104.     gxJob                docJob;
  1105.  
  1106. //    If we have a non-nil WindowPtr, set up our edit menu record and handle the job
  1107. //    format dialog.  Remember to check for errors.
  1108.  
  1109.     if ( wind != NULL )
  1110.     {
  1111.         docJob = GetWindowGXJob(wind);
  1112.         SetUpGXEditMenuRec(&edMenuRec);
  1113.         
  1114.         // Un-hilite menu
  1115.         HiliteMenu(0);
  1116.  
  1117.         // Disable the file menu while dialog is up
  1118.         DisableItem(gShellMenuHandles[kFileMenu], 0);
  1119.         
  1120.         *result = GXJobDefaultFormatDialog(docJob, &edMenuRec);
  1121.         err = GXGetJobError(docJob);
  1122.         
  1123.         // Enable the file menu
  1124.         EnableItem(gShellMenuHandles[kFileMenu], 0);
  1125.         DrawMenuBar();
  1126.     }
  1127.     
  1128.     return err;
  1129. }
  1130.  
  1131. /**\
  1132. |**| ---------------------------------------------------------------------
  1133. |**| DoPrinting()
  1134. |**| This routine performs GX's equivalent of the Print Job Dialog
  1135. |**| (PrJobDialog) call of the old printing architecture, and then prints
  1136. |**| the document if the user wants to.
  1137. |**| ---------------------------------------------------------------------
  1138. \**/
  1139. OSErr DoGXPrinting (WindowPtr wind)
  1140. {
  1141.     OSErr            err = noErr;
  1142.     gxDialogResult    result;
  1143.     gxEditMenuRecord    edMenuRec;
  1144.     gxJob                docJob;
  1145.  
  1146. //    If we have a non-nil WindowPtr, set up our edit menu record and handle the print
  1147. //    job dialog.  Remember to check for errors.  If no errors occur, and the user clicks
  1148. //  ok, print the window's document.
  1149.  
  1150.     if ( wind != NULL )
  1151.     {
  1152.         docJob = GetWindowGXJob(wind);
  1153.         
  1154.         SetUpGXEditMenuRec(&edMenuRec);
  1155.         
  1156.         // Un-hilite menu
  1157.         HiliteMenu(0);
  1158.  
  1159.         // Disable the file menu while dialog is up
  1160.         DisableItem(gShellMenuHandles[kFileMenu], 0);
  1161.         
  1162.         result = GXJobPrintDialog(docJob, &edMenuRec);
  1163.         err = GXGetJobError(docJob);
  1164.         
  1165.         // Enable the file menu
  1166.         EnableItem(gShellMenuHandles[kFileMenu], 0);
  1167.         DrawMenuBar();
  1168.         
  1169.         if ( (result == gxOKSelected) && (err == noErr) )
  1170.             err = AppPrintOne(wind);
  1171.     }
  1172.     
  1173.     return err;
  1174. }
  1175.  
  1176.  
  1177.  
  1178. /**\
  1179. |**| ---------------------------------------------------------------------
  1180. |**| DoPrintOne()
  1181. |**| This routine prints one copy of the window's document using whatever
  1182. |**| job and format is currently attached to it.  (If the window were just
  1183. |**| created and then the user selected Print One w/o first selecting Page
  1184. |**| Setup…, the system default job and format are stored with this document.
  1185. |**| ---------------------------------------------------------------------
  1186. \**/
  1187. OSErr DoGXPrintOne (WindowPtr wind, gxShape page)
  1188. {
  1189.     OSErr        err = noErr;
  1190.     gxJob        docJob;
  1191.     Str255        title;
  1192.     DocHandle    doc;
  1193.  
  1194. //    If we have a non-nil document, start the print job, print a page and then finish
  1195. //    the job.  Since we have just a one page document, we don't bother counting pages.
  1196. //    Remember to check those errors!
  1197.     
  1198.     doc = GetWindowDoc(wind);
  1199.     if ( doc != nil )
  1200.     {
  1201.         docJob = (*doc)->docJob;
  1202.         GetWTitle(wind, title);
  1203.         
  1204.         GXStartJob(docJob, title, 1);
  1205.         err = GXGetJobError(docJob);
  1206.         
  1207.         if ( err == noErr )
  1208.         {
  1209.               GXPrintPage(docJob, 1, GXGetJobFormat(docJob, 1), page);
  1210.             err = GXGetJobError(docJob);
  1211.         }
  1212.         
  1213.         GXFinishJob(docJob);
  1214.         if ( err == noErr )
  1215.             err = GXGetJobError(docJob);
  1216.     }
  1217.     return err;
  1218. }
  1219.  
  1220.  
  1221.